#include <QFile>
#include <QDateTime>
#include <QTextStream>

#include "SudokuData.h"
#include "SudokuSolver.h"

int main(/*int argc, char* argv[]*/)
{
    QString filePathTestSuite("../data/");
    //QString fileNameTestSuite("templaters.sdm");
    //QString fileNameTestSuite("TareksPearly1800.sdm");
    QString fileNameTestSuite("top50000.sdm");
    //QString fileNameTestSuite("TareksPearly5600.sdm");

    int notValidOnStartCount = 0;
    int solvedCount = 0;
    int notSolvedCount = 0;
    int badlySolvedCount = 0;

    int emptyCount = 0;

    QFile* fileTestSuite = new QFile (filePathTestSuite + fileNameTestSuite);

    if ( !fileTestSuite->open(QIODevice::ReadOnly) )
        qFatal("cannot open test suite");

    QString logFileName = "sudoku_" + QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") + ".log";
    QFile* logFile = new QFile(logFileName);

    if ( !logFile->open ( QIODevice::WriteOnly | QIODevice::Text ) )
        qFatal("cannot open log file");

    SudokuSolver solver;

    QTextStream stream(logFile);

    stream << "test suite: " << filePathTestSuite << fileNameTestSuite << endl;
    stream << "start time: " << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << endl;

    QTime startTime;
    startTime.start();

    QByteArray line;
    while(!fileTestSuite->atEnd())
    {
        line = fileTestSuite->readLine();
        if(line.length() < 1)
        {
            qDebug() << "wrong line";
            continue;
        }
        QString sudNumbers(line);
        SudokuData sudoku(sudNumbers);

        if(!sudoku.isValid())
        {
            qDebug() << "not valid sudoku";
            ++notValidOnStartCount;
            continue;
        }

        // Solve for all techniques, do not reset results
        solver.solve(&sudoku, MaskAll, false);

        // TODO results will be added also for badly solved - but this is ok for now

        if(sudoku.isFilled() && !sudoku.isSolved())
        {
            qDebug() << "badly solved";
            ++badlySolvedCount;
            continue;
        }

        if(sudoku.isSolved())
        {
            ++solvedCount;
        }
        else if(sudoku.isSolvable())
        {
            ++notSolvedCount;
        }
        else
        {
            qDebug() << "not solved - no solution!!!";
            ++badlySolvedCount;
            continue;
        }

        emptyCount += sudoku.getCellCount(Empty);
    }

    int elapsedTime = startTime.elapsed();

    fileTestSuite->close();

    stream << "not valid on start: " << notValidOnStartCount << endl;
    stream << "solved: " << solvedCount << endl;
    stream << "not solved: " << notSolvedCount << endl;
    stream << "badly solved: " << badlySolvedCount << endl;
    stream << endl;

    int filledCount = 0;
    int eliminatedCandidatesCount = 0;

    foreach(SudokuAbstractSolvingTechnique* technique, solver.getMap())
    {
        int count = solver.getTechniqueSolveCount(technique->getType());
        stream << technique->getName() << ": " << count << endl;
        switch(technique->getCategory())
        {
        case EliminateCandidate:
            eliminatedCandidatesCount += count;
            break;
        case FindValue:
            filledCount += count;
            break;
        default:
            break;
        }
    }

    stream << "empty: " << emptyCount << endl;
    stream << "filled: " << filledCount << endl;
    stream << "eliminatedCandidates: " << eliminatedCandidatesCount << endl;

    stream << "finish time: " << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << endl;
    stream << "working time (miliseconds): " << elapsedTime << endl;
    QTime elapsedTimeFormat(0, 0, 0);
    elapsedTimeFormat = elapsedTimeFormat.addMSecs(elapsedTime);
    stream << "working time: " << elapsedTimeFormat.toString("hh:mm:ss.zzz") << endl;

    logFile->close();

    return 0;
}
